home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc / Developer Documentation / Recipes, Tech Notes & Articles / Recipes / Data Interchange / Promises < prev    next >
Encoding:
Text File  |  1996-04-19  |  8.5 KB  |  263 lines  |  [TEXT/ttxt]

  1. OpenDoc™ Recipes
  2.  
  3.  
  4. Promises
  5. By The OpenDoc Design Team
  6. April 18, 1995.
  7.  
  8.  
  9. © 1993-1996  Apple Computer, Inc. All Rights Reserved.
  10. Apple, the Apple logo, AppleScript, Bento, Macintosh, QuickTime, and OpenDoc are 
  11. registered trademarks of Apple Computer, Inc.
  12. Finder, Mac, and QuickDraw are trademarks of Apple Computer, Inc. 
  13. SOM, SOMObjects, and System Object Model are licensed trademarks of IBM Corporation. 
  14.  
  15. Changes since DR4
  16.  
  17. • The example routine MyPartFulfillPromise now demonstrates the need to reposition the storage unit view to the beginning of the focused value so the actual data overwrites the existing promise data.
  18.  
  19. Changes since DR3
  20.  
  21. • Added a recipe for forcing a promise to be fulfilled.
  22.  
  23. • Added use of the kODPropCloneKindUsed property to the recipe for fulfilling a promise.
  24.  
  25. Changes since DR2
  26.  
  27. 1) Fixed refcounting method names.
  28. 2) Fixed parameter passing errors with SetValue and GetValue.
  29.  
  30. Overview
  31.  
  32. The basic mechanisms for transfering data between Parts are the Clipboard and Drag-and-Drop. If the data to be exported is very big, the part may choose to export the data as a promise. When the data is retrieved by the destination part, the source part will be requested to fulfill the promise it put out.
  33.  
  34. The format of a Promise is determined by the Part. The only restriction is that a Promise must be able to be written to a Storage Unit Value.
  35.  
  36. Recipes
  37.  
  38. Putting out a promise:
  39.  
  40. The following code fragment shows how a Part can put out a Promise in response to a mouse down event and a Drag is going to be initiated. (This recipe can also be used to put out a promise to the Clipboard).
  41.  
  42. ODBoolean MyPartHandleDragging(MyPart* somSelf,
  43.                                     Environment* ev,
  44.                                     ODFacet* facet,
  45.                                     ODPoint where,
  46.                                     ODEventData event)
  47. {
  48.  
  49.     ........
  50.     // Get the ODDragAndDrop object from the session.
  51.  
  52.     ODDragAndDrop* dragAndDrop =
  53.             this->GetStorageUnit(ev)->GetSession(ev)->GetDragAndDrop(ev);
  54.  
  55.     // Reinitialize the ODDragAndDrop object.
  56.  
  57.     dragAndDrop->Clear(ev);
  58.  
  59.     // Get the Storage Unit where data for dragged objects is going to be     
  60.     // written.
  61.  
  62.     ODStorageUnit* storageUnit = dragAndDrop->GetContentStorageUnit(ev);
  63.  
  64.     // Focus the Storage Unit to the Property.
  65.  
  66.     storageUnit->Focus(ev,
  67.                             kODPropContents,
  68.                             kODPosUndefined,
  69.                             kODNULL,
  70.                             0,
  71.                             kODPosUndefined);
  72.  
  73.     // Prepare the promise. This section is Part specific.
  74.  
  75.     MyPromise    promise = .......
  76.  
  77.  // Put the promise data in an ODByteArray.
  78.  ODByteArray ba;
  79.  ...
  80.  
  81.     // Put out the promise.
  82.  
  83.     storageUnit->SetPromiseValue(
  84.                             ev,
  85.                             kAppleText,                                            // type of promised data
  86.                             0,                                                                                // offset
  87.                             &ba,                                                         // promise
  88.                             fPartWrapper);                                // source part
  89.  
  90.     // Initiate the Dragging
  91.     // Follow the drag and drop recipe.
  92.     .......
  93.  
  94. );
  95.  
  96. Getting Data From a Value with a Promise:
  97.  
  98. When the destination part retrieves the data (using ODStorageUnit::GetValue or ODStorageUnit::GetSize), the source part will be called to fulfill the promise. The destination part does not even know that the fulfilment of a promise is taking place.
  99.  
  100. The following is what the code for the destination part might look like. The same code is used whether the Value contains a promise or not.
  101.  
  102. ODDropResult YourPartDrop(YourPart* somSelf,
  103.                                 Environment* ev,
  104.                                 ODDragItemIterator* dropInfo,
  105.                                 ODFacet* facet,
  106.                                 ODPoint where)
  107.  
  108. {
  109.  
  110.     ODDropResult        dropResult = kODDropFail;
  111.     ODStorageUnit*    dropSU;
  112.     ODBoolean        notDone = kODTrue;
  113.  
  114.     // iterate through the types and find a desired type
  115.  
  116.     for (dropSU = dropInfo->First(ev);
  117.             dropInfo->IsNotComplete(ev) && notDone;
  118.             dropSU = dropInfo->Next(ev))
  119.     {
  120.         // If the desired type exists, import the data.
  121.  
  122.         if (dropSU->Exists(ev, kODPropContents, kAppleText, 0) == kODTrue) {
  123.  
  124.             // Focus to the property and value containing the desired data.
  125.  
  126.             dropSU->Focus(ev,
  127.                             kODPropContents,
  128.                             kODPosUndefined,
  129.                             kAppleText,
  130.                             0,
  131.                             kODPosUndefined);
  132.  
  133.             // Get the size of the data.
  134.  
  135.             // **** Note that the promise is being fulfilled here. But this Part
  136.             // **** does not even realize that.
  137.  
  138.             ODULong size = dropSU->GetSize(ev);
  139.  
  140.             // Create an ODByteArray to hold the returned data. The fields will be filled out by GetValue.
  141.             ODByteArray ba;
  142.  
  143.             storageUnit->GetValue(ev, size, &ba);
  144.  
  145.             // Put the data into the part’s content.
  146.  
  147.             ......
  148.  
  149.             // Dispose the byte array buffer.
  150.  
  151.             ODDisposePtr(ba._buffer);
  152.  
  153.             // Stop the iteration.
  154.  
  155.             notDone = kODFalse;
  156.  
  157.             // Set up drop result appropriately.
  158.  
  159.             dropResult = kODDropCopy;
  160.  
  161.         }
  162.  
  163.     }
  164.  
  165.     // Return the appropriate result code.
  166.  
  167.     return dropResult;
  168.  
  169. }
  170.  
  171. Fulfilling a Promise
  172.  
  173. The following code fragment is an example of what the source part might do in response to a request to fulfull a promise.
  174.  
  175. Parts must use the correct clone kind in their call to BeginClone when fulfilling a promise.  All parts should check for the presense of a kODPropCloneKindUsed property in the target storage unit.  If this property is present, the clone kind value there should be used; otherwise, kODCloneCopy should be used.  
  176.  
  177. (Parts that don't support linking don't have to worry about writing a kODPropCloneKindUsed property.  Parts that do support linking and embedding are referred to the Linking recipes for more information about the conditions when a part should write a kODPropCloneKindUsed property.)
  178.  
  179. void MyPartFulfillPromise(MyPart* somSelf,
  180.                                 Environment* ev,
  181.                                 ODStorageUnitView* promiseSUView)
  182.  
  183. {
  184.      // Do a check first to see whether it is the right size.
  185.      ODULong size = promiseSUView->GetSize(ev);
  186.  
  187.      if (size == sizeof(MyPromise))
  188.   {
  189.           // Get the Promise.
  190.           // Either GetValue or GetPromiseValue can be used here.
  191.           // OpenDoc ensures that if GetValue is used, there will be no infinite recursion
  192.           // (i.e., GetValue -> FulfillPromise -> GetValue -> FulFillPromise).
  193.  
  194.           // Set up the byte array for promise.
  195.           MyPromise    promise;
  196.           ODByeArray promiseByteArray;
  197.           promiseByteArray._length = promisedDataSize;
  198.           promiseByteArray._maximum = promisedDataSize;
  199.           promiseByteArray._buffer = &promise;
  200.  
  201.           promiseSUView->GetValue(ev, (ODValue) &promiseByteArray);
  202.  
  203.           // Get the Promised Data using the Promise.
  204.           // This section is part-specific.
  205.  
  206.           TempODPtr promisedData = ......(promise);    // automatically disposed
  207.  
  208.           // Determine the clone kind to use in cloning content to fulfill the promise
  209.           ODCloneKind cloneKind = kODCloneCopy;
  210.           ODStorageUnit* promiseSU = promiseSUView->GetStorageUnit(ev);
  211.           if ( ODSUExistsThenFocus(ev, promiseSU, kODPropCloneKindUsed, kODCloneKind) )
  212.                   cloneKind = ODGetULongProp(ev, promiseSU, kODPropCloneKindUsed, kODCloneKind);
  213.  
  214.     // Begin a clone transaction
  215.     // (Not necessary in this simple example because no objects are cloned,
  216.     // but this demonstrates the correct way to setup a cloning transaction.)
  217.     ODDraft* myDraft = somSelf->GetStorageUnit(ev)->GetDraft(ev);
  218.     ODDraftKey draftKey = 0;
  219.  
  220.     ODVolatile(myDraft);
  221.     ODVolatile(draftKey);
  222.  
  223.     draftKey = myDraft->BeginClone(ev, promiseSU->GetDraft(ev), kODNULL, cloneKind);
  224.  
  225.     TRY
  226.  
  227.                   // Set up the byte array for promisedData.
  228.                   ODByeArray promisedDataByteArray;
  229.                   promisedDataByteArray._length = promisedDataSize;
  230.                   promisedDataByteArray._maximum = promisedDataSize;
  231.                   promisedDataByteArray._buffer = promisedData;
  232.  
  233.                   // Write the promised data back to the Value.
  234.                   // One can use use the promiseSUView to get the Storage Unit and write out
  235.                   // other Properties and Values other than the one refered to by promiseSUView.
  236.                   // Be sure to reposition to the beginning of the value to overwrite existing
  237.                   // promise data.
  238.                   promiseSUView->SetOffset(ev, 0);
  239.                   promiseSUView->SetValue(ev, (ODValue) &promisedDataByteArray);
  240.  
  241.     CATCH_ALL
  242.  
  243.       myDraft->AbortClone(ev, draftKey);
  244.       RERAISE;
  245.  
  246.     ENDTRY
  247.  
  248.     myDraft->EndClone(ev, draftKey);
  249.      }
  250.      else
  251.   {
  252.           // Simply delete the promise.
  253.           promiseSUView->DeleteValue(ev, size);
  254.  
  255.           // The destination will simply see a Value with no content.
  256.           // It is the responsibility of the destination part to handle invalid values.
  257.           // This is no different from the general case without promises.
  258.      }
  259. }
  260.  
  261. Forcing Promise Fulfillment
  262.  
  263. There are times when your part might need to force the fulfillment of a promise it has written, before another part actually tries to read the data.  An example of this might be when your part takes some action that would prevent it from fulfilling the promise in the future.  The simplest way for a part to force a promise to be fulfilled is to focus on the promised property/value and call the storage unit routine GetSize.